package cn.kwq.project_manger.aop.aspect;

import cn.hutool.core.util.StrUtil;
import cn.kwq.project_manger.aop.annotations.Idempotency;
import cn.kwq.project_manger.aop.annotations.LimitRequest;
import cn.kwq.project_manger.exception.IdempotencyException;
import cn.kwq.project_manger.exception.RequestLimitException;
import cn.kwq.project_manger.utils.IPUtils;
import com.alibaba.fastjson2.JSONObject;
import lombok.extern.slf4j.Slf4j;
import net.jodah.expiringmap.ExpirationPolicy;
import net.jodah.expiringmap.ExpiringMap;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;

/**
 * 幂等性校验 ExpiringMap版本，不带redis
 */
@Aspect
@Component
@Slf4j
public class IdempotencyAspect {


    private static ConcurrentHashMap<String, ExpiringMap<String, String>> connMap = new ConcurrentHashMap<>();
    private static final Object lock = new Object();

    private static final String str="requestOnce";

    // 定义切点
    // 让所有有@LimitRequest注解的方法都执行切面方法
    @Pointcut("@annotation(idempotency)")
    public void excudeService(Idempotency idempotency) {
    }




    @Around(value = "excudeService(idempotency)", argNames = "pjp,idempotency")
    public Object doAround(ProceedingJoinPoint pjp, Idempotency idempotency) throws Throwable {

        // 获得request对象
        RequestAttributes req = RequestContextHolder.getRequestAttributes();
        ServletRequestAttributes sReq = (ServletRequestAttributes) req;
        HttpServletRequest request = sReq.getRequest();


        //获取请求的路径作为key
        String requestURI = request.getRequestURI();

        //获取token
        String token = request.getHeader("token");

        // 获取Map对象， 如果没有则返回默认值
        ExpiringMap<String, String> idempotencyMap =
                connMap.getOrDefault(requestURI, ExpiringMap
                        .builder()
                        .variableExpiration()
                        .build());


        String tokenOnMap;
        //保证只有一个线程获取到tokenOnMap
        synchronized (lock) {
            // 第一个参数是key， 第二个参数是默认值
            tokenOnMap = idempotencyMap.getOrDefault(token, null);
        }

        //空的的话证明第一次调用
        if (tokenOnMap == null || StrUtil.isBlank(tokenOnMap)) {
            // result的值就是被拦截方法的返回值//执行方法
            Object result = pjp.proceed();

            idempotencyMap.put(token, str, ExpirationPolicy.CREATED, idempotency.time(), TimeUnit.MILLISECONDS);

            connMap.put(requestURI, idempotencyMap);
            return result;
        } else {
            throw new IdempotencyException(idempotency.msg());
        }


    }



}
